package ar.com.arkios.kfconTraductor;

import ar.com.arkios.j4d.opException;
import ar.com.arkios.kfcon4d.dao.CalibreDAO;
import ar.com.arkios.kfcon4d.dao.CodigoEANDAO;
import ar.com.arkios.kfcon4d.dao.ContramarcaDAO;
import ar.com.arkios.kfcon4d.dao.EmbalajeDAO;
import ar.com.arkios.kfcon4d.dao.EnvaseDAO;
import ar.com.arkios.kfcon4d.dao.EspecieDAO;
import ar.com.arkios.kfcon4d.dao.LeyendaEtiquetaDAO;
import ar.com.arkios.kfcon4d.dao.LoteDAO;
import ar.com.arkios.kfcon4d.dao.OrdenDAO;
import ar.com.arkios.kfcon4d.dao.PesoStandarDAO;
import ar.com.arkios.kfcon4d.dao.VariedadDAO;
import ar.com.arkios.kfconmodelo.modelo.Almacen;
import ar.com.arkios.kfconmodelo.modelo.Calibre;
import ar.com.arkios.kfconmodelo.modelo.CodigoEAN;
import ar.com.arkios.kfconmodelo.modelo.Contramarca;
import ar.com.arkios.kfconmodelo.modelo.Embalaje;
import ar.com.arkios.kfconmodelo.modelo.Envase;
import ar.com.arkios.kfconmodelo.modelo.Especie;
import ar.com.arkios.kfconmodelo.modelo.LeyendaEtiqueta;
import ar.com.arkios.kfconmodelo.modelo.Lote;
import ar.com.arkios.kfconmodelo.modelo.Orden;
import ar.com.arkios.kfconmodelo.modelo.PesoStandar;
import ar.com.arkios.kfconmodelo.modelo.Variedad;
import ar.com.arkios.kfconsap.excepciones.SapComunicationException;
import ar.com.arkios.kfconsap.excepciones.SapGeneralException;
import ar.com.arkios.kfconsap.conexion.SAPConnection;
import ar.com.arkios.kfconsap.rfc.ContramarcaReadRFC;
import ar.com.arkios.kfconsap.rfc.DatosCentroReadRFC;
import ar.com.arkios.kfconsap.rfc.EANReadRFC;
import ar.com.arkios.kfconsap.rfc.EnvaseReadRFC;
import ar.com.arkios.kfconsap.rfc.EspecieReadRFC;
import ar.com.arkios.kfconsap.rfc.EtiquetaReadRFC;
import ar.com.arkios.kfconsap.rfc.GenericRFC;
import ar.com.arkios.kfconsap.rfc.LotesCentrosReadRCF;
import ar.com.arkios.kfconsap.rfc.PesoStandarReadRFC;
import ar.com.arkios.kfconsap.rfc.VariedadReadRFC;
import java.util.List;
import org.apache.log4j.Logger;

/**
 *
 * @author Ale
 * @version 1.01
 * 
 */
public class SAPTo4DSecondVersion {

    private static final Logger myLogger = Logger.getLogger(SAPTo4DSecondVersion.class);
    
    private List <Especie> myEspecies;
    private List <Variedad> myVariedades;
    private List <Envase> myEnvases;
    private List <Contramarca> myContramarcas;
    private List <LeyendaEtiqueta> myEtiquetas;
    private List <CodigoEAN> myCodigosEan;
    private List <PesoStandar> myPesos;
    private List <Lote> myLotes;
    private List <Almacen> myAlmacenes;
    private List <Calibre> myCalibres;
    private List <Embalaje> myEmbalajes;
    private List <Orden> myOrdenes;
    
    private static final int TIMEOUT = 480000;//60*8=480 o sea 8 minutos
    private static final int TIMESLEEP = 50;

    public SAPTo4DSecondVersion() throws Exception {
     
        try {     
            //System.out.println("Conectando a SAP");
            this.myEspecies =  getEspeciesSAP();
            //System.out.println("Especies Descargadas: "+this.myEspecies.size());
            this.myVariedades =  getVariedadesSAP();
            //7System.out.println("Variedades Descargadas: "+this.myVariedades.size());
            this.myEnvases = getEnvasesSAP();
            //System.out.println("Envases Descargadas: "+this.myEnvases.size());
            this.myContramarcas = getContramarcasSAP();
            //System.out.println("Comntramarcas Descargadas: "+this.myContramarcas.size());
            this.myEtiquetas = getEtiquetasSAP();
            //System.out.println("Etiquetas Descargadas: "+this.myEtiquetas.size());
            this.myCodigosEan = getEANCodigosSAP();
            //System.out.println("EAN Descargadas: "+this.myCodigosEan.size());
            this.myPesos = getPesosSAP();
            //System.out.println("Pesos Descargadas: "+this.myPesos.size());
            this.readTablesWithParams();            
            this.myLotes = getLotesSAP();
            //System.out.println("Especies Descargadas: "+this.myLotes.size());
            SAPConnection.getInstance().close();            
            //System.out.println("Conexion con SAP Cerrada.");
        } catch (SapGeneralException e) {
            String mensaje = e.getMessage();
            myLogger.error("Error SAP: "+e.getMessage());
            try {
                SAPConnection.getInstance().close(); 
            } catch (SapComunicationException ex) {
                myLogger.error("Error al tratar de cerrar la conexión sap: " + ex.getMessage());
                mensaje += " - " + ex.getMessage();
            } finally {
                throw new Exception(mensaje);
            }
        }
        
    }
    
    
    private  List<Contramarca> getContramarcasSAP() throws SapGeneralException {
            ContramarcaReadRFC aContramarcaReadRFC = new ContramarcaReadRFC();
            executeRFC(aContramarcaReadRFC);
            aContramarcaReadRFC.getMyContramarcaDAO().findAll();
            return aContramarcaReadRFC.getMyContramarcaDAO().getMisContramarcas();    
    }
    public void saveContramarcas4D(boolean aBoolean) throws opException{
            ContramarcaDAO miContramarcaDAO = new ContramarcaDAO();
            miContramarcaDAO.setReescritura(aBoolean);
            miContramarcaDAO.saveAll(this.myContramarcas);
    }
    private List<Especie> getEspeciesSAP() throws  SapGeneralException {
        EspecieReadRFC aEspecieReadRFC = new EspecieReadRFC();
        executeRFC(aEspecieReadRFC);
        aEspecieReadRFC.getEspecieDAO().findAll();
        return aEspecieReadRFC.getEspecieDAO().getMisEspecies();    
    }
    public void saveEspecies4D(boolean aBoolean) throws opException{
        EspecieDAO aEspecieDAO = new EspecieDAO();
        aEspecieDAO.setReescritura(aBoolean);
        aEspecieDAO.saveAll(this.myEspecies);
    }
    private List <CodigoEAN> getEANCodigosSAP() throws  SapGeneralException {
        EANReadRFC aReadRFC = new EANReadRFC();
        executeRFC(aReadRFC);
        aReadRFC.getMyEANCodigoDAO().findAll();
        return aReadRFC.getMyEANCodigoDAO().getMisCodigosEAN();
    }
    public void saveEANCodigo4D(boolean aBoolean) throws opException{
        CodigoEANDAO aCodigoEANDAO = new CodigoEANDAO();
        aCodigoEANDAO.setReescritura(aBoolean);
        aCodigoEANDAO.saveAll(this.myCodigosEan);
    }
    private List <Envase> getEnvasesSAP() throws SapGeneralException {
        EnvaseReadRFC aEnvaseReadRFC = new EnvaseReadRFC();
        executeRFC(aEnvaseReadRFC);
        aEnvaseReadRFC.getMyEnvaseDAO().findAll();
        return aEnvaseReadRFC.getMyEnvaseDAO().getMisEnvases();
    }
    public void saveEnvases4D(boolean aBoolean) throws opException{
        EnvaseDAO aEnvaseDAO = new EnvaseDAO();
        aEnvaseDAO.setReescritura(aBoolean);
        aEnvaseDAO.saveAll(this.myEnvases);
    }
    private List <LeyendaEtiqueta> getEtiquetasSAP() throws SapGeneralException {
        EtiquetaReadRFC aEtiquetaReadRFC = new EtiquetaReadRFC();
        executeRFC(aEtiquetaReadRFC);
        aEtiquetaReadRFC.getMyTextoEtiquetaDAO().findAll();
        return aEtiquetaReadRFC.getMyTextoEtiquetaDAO().getMisLeyendasEtiquetas();
    }
    public void saveEtiquetas4D(boolean aBoolean) throws opException{
        LeyendaEtiquetaDAO aLeyendaEtiquetaDAO = new LeyendaEtiquetaDAO();
        aLeyendaEtiquetaDAO.setReescritura(aBoolean);
        aLeyendaEtiquetaDAO.saveAll(this.myEtiquetas);
    }
    private List <Variedad> getVariedadesSAP() throws SapGeneralException {
        VariedadReadRFC aVariedadReadRFC = new VariedadReadRFC();
        executeRFC(aVariedadReadRFC);
        aVariedadReadRFC.getMyVariedadDAO().findAll();
        return aVariedadReadRFC.getMyVariedadDAO().getMisVariedades();
    }
    public void savePesos4d(boolean aBoolean) throws opException {
        PesoStandarDAO aPesoStandarDAO = new PesoStandarDAO();
        aPesoStandarDAO.setReescritura(aBoolean);
        aPesoStandarDAO.saveAll(this.myPesos);
    }
    public void saveVariedad4D(boolean aBoolean) throws opException{
        VariedadDAO aVariedadDAO = new VariedadDAO();
        aVariedadDAO.setReescritura(aBoolean);
        aVariedadDAO.saveAll(this.myVariedades);
    }
    private void readTablesWithParams() throws SapGeneralException {
        DatosCentroReadRFC aDatosCentroReadRFC = new DatosCentroReadRFC();
        executeRFC(aDatosCentroReadRFC);
        aDatosCentroReadRFC.getMyAlmacenDAO().findAll();
        this.myAlmacenes = aDatosCentroReadRFC.getMyAlmacenDAO().getMisAlmacenes();
        //System.out.println("Alamcenes Descargadas: "+this.myAlmacenes.size());
        aDatosCentroReadRFC.getMyCalibreDAO().findAll();
        this.myCalibres = aDatosCentroReadRFC.getMyCalibreDAO().getMisCalibres();
        //System.out.println("Calibres Descargadas: "+this.myCalibres.size());
        aDatosCentroReadRFC.getMyEmbalajeDAO().findAll();
        this.myEmbalajes = aDatosCentroReadRFC.getMyEmbalajeDAO().getMisEmbalajes();
        //System.out.println("Embalajes Descargadas: "+this.myEmbalajes.size());
        aDatosCentroReadRFC.getMyOrdenDAO().findAll();
        this.myOrdenes = aDatosCentroReadRFC.getMyOrdenDAO().getMisOrdenes();
        //System.out.println("Ordenes Descargadas: "+this.myOrdenes.size());
    }
    public void saveAlmacenes4D(boolean aBoolean) throws opException{
        ar.com.arkios.kfcon4d.dao.AlmacenDAO almacenDAO = new ar.com.arkios.kfcon4d.dao.AlmacenDAO();
        almacenDAO.setReescritura(aBoolean);
        almacenDAO.saveAll(this.myAlmacenes);
    }
    public void saveCalibres4D(boolean aBoolean) throws opException{
        CalibreDAO aCalibreDAO = new CalibreDAO();
        aCalibreDAO.setReescritura(aBoolean);
        aCalibreDAO.saveAll(this.myCalibres);
    }
    public void saveEmbalaje4D(boolean aBoolean) throws opException {
        EmbalajeDAO aEmbalajeDAO = new EmbalajeDAO();
        aEmbalajeDAO.setReescritura(aBoolean);
        aEmbalajeDAO.saveAll(this.myEmbalajes);
    }
    public void saveOrdenes4D() throws opException{
        OrdenDAO aOrdenDAO = new OrdenDAO();
        aOrdenDAO.saveAll(this.myOrdenes);
    }
    private List <PesoStandar> getPesosSAP() throws SapGeneralException{
        PesoStandarReadRFC aPesoStandarReadRFC = new PesoStandarReadRFC();
        executeRFC(aPesoStandarReadRFC);
        aPesoStandarReadRFC.getMyPesoStandarDAO().findAll();
        return aPesoStandarReadRFC.getMyPesoStandarDAO().getMisPesosStandar();
    }
    private List <Lote> getLotesSAP() throws SapGeneralException {
        LotesCentrosReadRCF aLotesCentrosReadRCF = new LotesCentrosReadRCF();
        executeRFC(aLotesCentrosReadRCF);
        aLotesCentrosReadRCF.getMyLoteDAO().findAll();
        return aLotesCentrosReadRCF.getMyLoteDAO().getMisLotes();
    }
    public void saveLotes4D() throws opException {
        LoteDAO aLoteDAO = new LoteDAO();
        aLoteDAO.saveAll(this.myLotes);
    }
    
    private void executeRFC(GenericRFC rfc) {
        SAPExecuter executer = new SAPExecuter(rfc);
        long tiempoExecuter = 0;
        final long tiempoInicio = System.currentTimeMillis();
                
        executer.start();
        boolean entroAlMenosUnaVez = false;
        while ((tiempoExecuter < TIMEOUT) && (executer.isAlive())) {
            entroAlMenosUnaVez = true;
            tiempoExecuter = (System.currentTimeMillis() - tiempoInicio);
            try {
                Thread.sleep(TIMESLEEP);
            } catch (Exception e) {
                myLogger.error("executeRFC: No se pudo realizar la espera de ejecución de la RFC.");
                myLogger.error(e);
                throw new SapGeneralException("No se pudo realizar la espera de ejecución de la RFC.");
            }
        }
        
        if (executer.isAlive()) {
            myLogger.error("executeRFC: La operación de la RFC " + rfc.getClass().getSimpleName() + " tomó demasiado tiempo.");
            myLogger.error("info: Thread-ID: "+executer.getId() + " - Thread-State: " + executer.getState() + "EntroUnaVez: " + entroAlMenosUnaVez);
            throw new SapGeneralException("La operación de la RFC " + rfc.getClass().getSimpleName() + " tomó demasiado tiempo.");
        }
        
        String elStatus = "";
        try {
            elStatus = SAPConnection.getInstance().getMyStatus();
        } catch (SapComunicationException e) {
            myLogger.error("Error durante setMyStatus");
        }
        if (elStatus.isEmpty())
            myLogger.debug("executeRFC: Se ejecutó correctamente sin timeout la RFC " + rfc.getClass().getSimpleName());
        else {
            myLogger.debug("executeRFC: Se ejecutó con ERROR pero sin timeout la RFC " + rfc.getClass().getSimpleName());
            throw new SapGeneralException("Error en " + rfc.getClass().getSimpleName() + elStatus);
        }
    }

    
    private class SAPExecuter extends Thread {
        
        private final Logger myLogger = Logger.getLogger(SAPExecuter.class);
        
        private GenericRFC rfc;
        
        public SAPExecuter(GenericRFC rfc) {
            this.rfc = rfc;
        }

        @Override
        public void run() {
            try {
                //myLogger.info("SAPExecuter: inicia la RFC " + rfc.getClass().getSimpleName());
                this.rfc.executeFunction();
            } catch (SapGeneralException e) {
                try {
                    myLogger.error("SAPExecuter: Ocurrió un error al ejecutar la RFC " + rfc.getClass().getSimpleName());
                    SAPConnection.getInstance().setMyStatus(e.getMessage());
                } catch (SapComunicationException ex) {
                    myLogger.error("Error durante setMyStatus");
                }
            } catch (RuntimeException e) {
                try {
                    myLogger.error("SAPExecuter: RuntimeException al ejecutar la RFC " + rfc.getClass().getSimpleName());
                    SAPConnection.getInstance().setMyStatus(e.getMessage());
                } catch (SapComunicationException ex) {
                    myLogger.error("Error durante setMyStatus");
                }
            } catch (Throwable t) {// para que no se nos escape nada de nada
                try {
                    
                    myLogger.error("SAPExecuter: Ocurrió un error Throwable al ejecutar la RFC " + rfc.getClass().getSimpleName() + " - " + t.getMessage());
                    SAPConnection.getInstance().setMyStatus(t.getMessage());
                } catch (SapComunicationException ex) {
                    myLogger.error("Error durante setMyStatus");
                }
            }
            //myLogger.info("SAPExecuter: finaliza la RFC " + rfc.getClass().getSimpleName());
        }
        
    }   
}
